/*
 * volume.c
 *
 *  Created on: 2017年5月6日
 *      Author: chenss
 */


#include "io/volume.h"
#include "ctimer.h"
#include "utils.h"
#include "timer.h"

// 测量超时时长 （ms）
#define TIME_OUT_MS 20
#define _TIM_UPDATE_FREQ (1000 / TIME_OUT_MS)

enum Stage
{
    Stage_Init,
    Stage_Capture1,
    Stage_Finish,
    Stage_Timeout
};

//static Ctimer_t _timeout;
static volatile enum Stage _stage;
static bool _captureStarted;
static volatile uint32_t _icc, _ov;

void Volume_Init(void)
{
    TIM_ICInitTypeDef  TIM_ICInitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
//    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

    /* TIM1 clock enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

    /* GPIOA clock enable */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* TIM1 channel 2 pin (PE.11) configuration */
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* Connect TIM pins to AF2 */
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_2);

//    TIM_TimeBaseStructure.TIM_Prescaler = 10;
//    TIM_TimeBaseStructure.TIM_Period = (SystemCoreClock / 10 / _TIM_UPDATE_FREQ) - 1;
//    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
//    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//    TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);

    /* TIM1 configuration: Input Capture mode ---------------------
       The external signal is connected to TIM1 CH2 pin (PA.09)
       The Rising edge is used as active edge,
       The TIM1 CCR2 is used to compute the frequency value
    ------------------------------------------------------------ */

    TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge;
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICFilter = 0x0;
    TIM_ICInit(TIM1, &TIM_ICInitStructure);

    /* TIM enable counter */
    TIM_Cmd(TIM1, DISABLE);

    /* Enable the CC2 Interrupt Request */
    TIM_ITConfig(TIM1, TIM_IT_Update | TIM_IT_CC4, DISABLE);

    /* Enable the TIM1 global Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void TIM1_CC_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) //超时处理
    {
//        _stage = Stage_Timeout;
//        TIM_Cmd(TIM1, DISABLE);
        _ov += 1;
        TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
    }

    if (TIM_GetITStatus(TIM1, TIM_IT_CC4) == SET)
    {
        /* Clear TIM1 Capture compare interrupt pending bit */
        TIM_ClearITPendingBit(TIM1, TIM_IT_CC4);

        if(_stage == Stage_Init)
        {
//            _icc1 = TIM_GetCapture4(TIM1);

            TIM_SetCounter(TIM1, 0);
            _ov = 0;
            _stage = Stage_Capture1;
        }
        else if(_stage == Stage_Capture1)
        {
            _icc = TIM_GetCapture4(TIM1);
            _stage = Stage_Finish;
            TIM_Cmd(TIM1, DISABLE);
            TIM_ITConfig(TIM1, TIM_IT_Update | TIM_IT_CC4, DISABLE);
        }
    }
}

#if 0
static void _OnTimeout(void)
{
    if(_stage == Stage_Init)
    {
        TIM_Cmd(TIM1, DISABLE);
        TIM_ITConfig(TIM1, TIM_IT_CC4, DISABLE);
        _stage = Stage_Timeout;
    }

    Ctimer_Stop(& _timeout);
}
#endif

/**
 *
 * @return 筒容量(mm)
 */
int Volume_Get(void)
{
#define SOUND_SPEED 340

    float fd;
    int id;
    Timer_t timer;

//    debug("Volume detect\r\n");

    _stage = Stage_Init;
    _captureStarted = FALSE;
    _icc = 0;
    _ov = 0;
    TIM_ClearITPendingBit(TIM1, TIM_IT_Update | TIM_IT_CC4);
    TIM_ITConfig(TIM1, TIM_IT_Update | TIM_IT_CC4, ENABLE);
    TIM_SetCounter(TIM1, 0);
    TIM_Cmd(TIM1, ENABLE);

//    Ctimer_Start(& _timeout, 50, _OnTimeout, 0);
    GPIO_ResetBits(GPIOA, GPIO_Pin_12);
    Utils_DelayMs(1);
    GPIO_SetBits(GPIOA, GPIO_Pin_12);

    Timer_Set(& timer, 20);
    while(_stage < Stage_Finish)
    {
        if(Timer_Expired(& timer))
        {
            break;
        }
    }

    if((_stage != Stage_Finish) || (_icc == 0))
    {
//        debug("Volume detect timeout!\r\n");
        return 0;
    }

    _icc += (_ov * 65536);
//    debug("icc = %u\r\n", _icc);

    fd = 1000 * 340.0 * _icc /(2.0 * SystemCoreClock);
    id = (int) fd;
    debug("Volume %d(mm)\r\n", id);
    return id;
}
